home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
qualitas
/
dpmilib.txt
< prev
next >
Wrap
Text File
|
1994-04-22
|
30KB
|
749 lines
(C) Copyright 1992, Qualitas, Inc. All Rights Reserved
Qualitas C/C++ Libraries for DPMI
** Contents of this file **
1. Introduction
2. Requirements
3. Limitations
4. Building the Example Programs
5. Building the DPMI libraries
6. Using the C library
7. Using the C++ class library
**********************************************************************
1. Introduction
The Qualitas C/C++ Libraries for DPMI provide the C/C++ programmer with
easy access to DPMI. The purpose of the libraries is to allow developers
to gain familiarity with DPMI concepts, to aid in understanding of how
DPMI can be used, and to serve as a platform for experimentation with
DPMI hosts via the creation of small model C/C++ applications.
The directories are structured as follows:
top
|
+------------------+--------+---------+------------------+
| | | |
BC2 BC3 MSC6 MSC7
| | | |
+-------+------+ +-------+------+ +-------+------+ +-------+------+
| | | | | | | | | | | | | | | |
LIB | | | LIB | | | LIB | | | LIB | | |
LIBSRC | | LIBSRC | | LIBSRC | | LIBSRC | |
INCLUDE | INCLUDE | INCLUDE | INCLUDE |
EXAMPLES EXAMPLES EXAMPLES EXAMPLES
For convenience of installation, the distribution provides a copy of the
source code for the libraries and examples in each compiler directory.
The primary differences between compiler directories are (1) the makefiles
differ, and (2) some of the source code distributed with the compilers
has been modified for operation in conjunction with the DPMI libraries,
and those modules are included in their respective directories.
\ this README file
.\MSC7LIB Microsoft C/C++ 7.0 support
.\MSC6LIB Microsoft C 6.0 support
.\BC3LIB Borland C/C++ 3.0 support
.\BC2LIB Borland C/C++ 2.0 support
.\xxx\LIBSRC Source code for the DPMI libraries
.\xxx\INCLUDE Header files required for source and examples
.\xxx\EXAMPLES Source code for the example programs
We have include a batch file to simplify installation.
Use the following syntax to install the Qualitas DPMI Library:
INSTALL path library [source drive]
where "path" points to the directory into which the DPMI library
will be installed and "library" is the specific version of the DPMI
library you wish installed. Source drive is the floppy drive
echo from which you are installing (default = A)
Select the library from the following:
BC2 Borland C++ version 2.x comaptible library
BC3 Borland C++ version 3.x comaptible library
MSC6 Microsoft C verson 6.x comaptible library
MSC7 Microsoft C verson 7.x comaptible library
Example: INSTALL C:\TOOLS MSC6 B
would install the Microsoft C 6 compatible DPMI library from B:
to C:\TOOLS.
If you prefer to install the library manually, use the following
commands. This example would install the Borland C++ version 3.0
library:
C> md DPMILIBS
C> cd DPMILIBS
C:\DPMILIBS> cd a:\BC3LIB
C:\DPMILIBS> xcopy a: /s
**********************************************************************
2. Requirements
The requirements depend upon which C compiler you are using:
Compiler Processor Assembler Linker Librarian
-------- --------- --------- ------ ---------
Microsoft v7 80386 MASM 6.0 LINK 5.30 LIB 3.20
Microsoft v6 80286 MASM 6.0+5.1 LINK 5.10 LIB 3.18
Borland v3 80286 TASM 3.0 TLINK 5.0 TLIB 3.02
Borland v2 80286 TASM 2.5 TLINK 4.0 TLIB 3.02
NOTE: The librarian and assembler are only required if you wish to
rebuild the libraries. They are not required to build the
examples or other applications.
Each compiler requires the small model libraries. The Microsoft compilers
require the include files for the startup source to rebuild the DPMI
libraries.
**********************************************************************
3. Limitations
* Only small model is supported. It is possible, however, to use
far pointers that are dynamically created, for example, by using
the MK_FP macro. Statically initialized far pointers will work
only if they refer to the default code segment or the default data
segment.
* Floating point is not supported. The run-time requirements create
complications which are beyond the scope of this implementation.
* Errors may result from use of run time library functions that require
running clean-up routines at exit time, if such clean-up routines
utilize real mode far pointers created prior to entering protected mode.
**********************************************************************
4. Building the Example Programs
The .\EXAMPLES directory contains the following programs:
* HELLO.C A simple C program that illustrates how to enter
protected mode, and how to call the DPMI C library.
* QSORT.C A program that sorts stdin to stdout. It uses DPMI to
allocate buffers, which enables it to sort very
large files in memory.
* XMEM.CPP A C++ program that illustrates the use of the classes in
the DPMI class libraries that are related to memory usage.
* XINTR.CPP A C++ program that illustrates the use of the classes in
the DPMI class libraries that are related to interrupt handling.
* XREAL.CPP A C++ program that illustrates the use of the classes in
the DPMI class libraries that are related to calling real
mode functions and real mode call-backs.
* XCEPT.CPP A C++ program that illustrates the use of the classes in
the DPMI class libraries that are related to exception handling.
More detail about using the libraries and classes is found below.
** To build the examples with Microsoft C 7.0
- Your current directory must be the MSC7\EXAMPLES directory.
- CL and LINK for MS C 7.0 must be on your path.
- Your INCLUDE and LIB environment variables must be set for
a normal MS C 7.0 build.
- Issue the command NMAKE.
** To build the examples with Microsoft C 6.0
NOTE: the C++ examples are not built for MS C 6.0
- Your current directory must be the MSC6\EXAMPLES directory.
- CL and LINK for MS C 6.0 must be on your path.
- Your INCLUDE and LIB environment variables must be set for
a normal MS C 6.0 build.
- Issue the command NMAKE.
** To build the examples with Borland C++ 3.0
- Your current directory must be the BC3\EXAMPLES directory.
- BCC and TLINK for BC++ 3.0 must be on your path.
- The BC3LIB variable in the MAKEFILE must be set to the
directory where your Borland C++ libraries
reside. Edit MAKEFILE and locate the BC3LIB line.
Change the right hand side of the statement
as needed for your environment.
- Issue the command MAKE.
** To build the examples with Borland C++ 2.0
- Your current directory must be the EXAMPLES directory.
- BCC and TLINK for BC++ 2.0 must be on your path.
- The BC2LIB variable in the MAKEFILE must be set to the
directory where your Borland C++ libraries
reside. Edit MAKEFILE and locate the BC2LIB line.
Change the right hand side of the statement
as needed for your environment.
- Issue the command MAKE.
**********************************************************************
5. Building the DPMI libraries
It is not necessary to rebuild the libraries in order to build the examples
or to build other applications. However, in the event you wish to modify
the library source code, the following instructions are provided for
rebuilding the libraries:
** To build the libraries with Microsoft C 7.0
- Your current directory must be the MSC7\LIBSRC directory.
- CL, MASM (v6.0) and LINK for MS C 7.0 must be on your path.
- Your INCLUDE and LIB environment variables must be set for
a normal MS C 7.0 build.
- The C7DIR variable in the makefile must
be set to the directory where your Microsoft C++ distribution
resides. Edit MAKEFILE and locate the C7DIR= line
Change the right hand side of the statement
as needed for your environment.
- Issue the command NMAKE.
** To build the libraries with Microsoft C 6.0
NOTE: the C++ libraries are not built for MS C 6.0
- Your current directory must be the MSC6\LIBSRC directory.
- CL and LINK for MS C 6.0 must be on your path.
- Your INCLUDE and LIB environment variables must be set for
a normal MS C 6.0 build.
- The C6DIR variable in the MAKEFILE must
be set to the directory where your Microsoft C distribution
resides. Edit MAKEFILE and locate the C6DIR= line.
Change the right hand side of the statement
as needed for your environment.
- The ASM51 variable in the MAKEFILE must be set for the
5.1 version of MASM in order to assemble the MS C 6.0 startup code.
- Issue the command NMAKE.
** To build the libraries with Borland C++ 3.0
- Your current directory must be the BC3\LIBSRC directory.
- BCC, TASM, and TLINK for BC++ 3.0 must be on your path.
- Issue the command MAKE.
** To build the libraries with Borland C++ 2.0
- Your current directory must be the LIBSRC directory.
- BCC, TASM, and TLINK for BC++ 2.0 must be on your path.
- Issue the command MAKE.
**********************************************************************
6. Using the C Library
There is roughly a one-to-one mapping between the set of DPMI version 0.9
functions and the entry points of the DPMI C library. A copy of the
DPMI specification may be a useful reference.
A set of three higher level calls is provided for simplified memory
management. DPMImalloc(), DPMIresize(), and DPMIfree() provide a means
to allocate and address blocks of memory allocated from DPMI. These
calls are implemented using lower level calls of the library. Refer to
DPMIMALL.C in the LIBSRC directory to see how.
Definitions for the C library are found in INCLUDE\DPMI.H. This file
contains structure definitions, function prototypes, and descriptions
of each call.
Two example programs are provided in the EXAMPLES directory. HELLO.C shows
basic usage: how to enter protected mode and call a library routine.
QSORT.C is a useful utillity for sorting large files, which is built
using the DPMImalloc family of memory management routines.
**********************************************************************
7. Using the C++ Class Library
The class library provides a set of C++ classes that abstract several
important DPMI objects. The header files provide descriptions and
brief examples on using the classes.
Definitions for the DPMI classes are contained in these header files,
found in the INCLUDE directory:
DPMIHOST.H DPMI host class
SEGMENT.H All memory related classes
REALPROC.H Real procedure class
REALINT.H Real interrupt class
CALLBACK.H Real mode call-back class
DPMIINT.H Interrupt handler classes
EXCEPTIO.H Processor exception handler class
General note: Many of the constructors make calls to DPMI. Since the
constructors for statically allocated class instances are called prior
to main(), declaring instances from the DPMI classes statically may
result in attempting to call DPMI prior to entering protected mode,
which probably will cause a system crash. Therefore, DPMI objects
should be created dynamically, either as automatics (on a function's
local stack frame) or with the new operator. It is certainly allowable
to statically allocate pointers to DPMI objects, and initialize them
after entering protected mode in order to gain global addressability.
*--------------------------------------------------------------------
Header File: DPMIHOST.H See examples XMEM, XREAL, XCEPT, XINTR
Classes Members
------- -------
DPMIhost
DPMIhost Constructor; checks presence of a
DPMI host, and gathers needed
host information.
getStatus Used to verify detection of DPMI host
enterProtectedMode Makes the initial switch into
protected mode.
getProcessor Returns processor code
getVersion Returns major and minor version.
getSelectorDelta Returns delta between consecutive
selectors.
When you declare a DPMIhost object in your program, the constructor tests
for the presence of a DPMI host on your system. If found, the constructor
collects information from the host needed for the switch into protected mode.
You can determine the success or failure of the constructor by calling the
getStatus member, which returns DPMIok if the constructor found a DPMI host
and was successfully initialized. The members getProcessor, getVersion,
and getSelectorDelta simply return the appropriate host parameters.
You use the member enterProtectedMode for the initial switch into protected
mode, and after that it should not be called. It first allocates a block
of DOS memory to satisfy the host's private data area requirements. It then
calls the mode switch entry point obtained by the constructor. When this
returns, the processor is running in protected mode. Finally, this member
relocates the executable image for protected mode operation (see
Implementation Notes for details). The enterProtectedMode member returns
TRUE if the processor is successfully switched to protected mode.
*--------------------------------------------------------------------
Header File: SEGMENT.H See example XMEM
Classes Members
------- -------
Block
Block Constructor; allocates raw block
of memory from DPMI.
~Block Destructor; release block to DPMI
setSize Resize function reallocates block.
blockHandle Returns block handle.
blockSize Returns block size.
blockBase Returns base linear address.
AbstractSegment
segmentSize Returns size of segment.
segmentBase Returns base of segment.
resize Resizes segment.
move Changes segment base.
operator+ Adds a segment property.
operator- Removes a segment property.
queryProp Tests for segment property.
Segment
: AbstractSegment
Segment(void) Generic constructor.
Segment(selector_t) Specific descriptor.
Segment(AbstractSegment&) Alias to existing segment.
~Segment(void); Releases descriptor to DPMI.
CommonRealSegment
: AbstractSegment
CommonRealSegment Constructor
DOSMemory
: AbstractSegment
DOSMemory Constructor
~DOSMemory Destructor
HugeSegment
: AbstractSegment
HugeSegment Constructor
~HugeSegment Destructor
MemorySegment
: AbstractSegment, Block
MemorySegment(uShort) Constructor
MemorySegment(uShort, Constructor for specific descriptor
selector_t)
~MemorySegment Destructor-frees block and descriptor
HugeMemorySegment
: HugeSegment, Block
The various memory classes provide structured access to DPMI's memory
management facilities.
Note that of the classes defined, DOSMemory, MemorySegment, and
HugeMemorySegment are unique in they that combine allocated memory and
descriptors to address that memory. The other classes are either
just memory (e.g. Block) or just descriptors (e.g. Segment, HugeSegment).
The distinctions between memory and descriptors are important to
the conceptualization of the memory classes.
*......................................................................
The Block class corresponds to raw memory blocks allocated via DPMI
function 501h. Defined operations on Blocks are limited to resize,
and free. The class also supports query of the DPMI memory handle and
query of the block size. Blocks by themselves are not especially useful,
since the memory is not addressable. Its purpose is to serve as a
base class for MemorySegment and HugeMemorySegment.
*......................................................................
AbstractSegment is an abstract class the corresponds to a descriptor.
DPMI provides several means to create descriptors, all with slightly
different behavior. Although most members of AbstractSegment are pure,
a key member that it does implement is ptrTo, which returns a far
pointer that may be used to reference the linear address space that
the corresponding descriptor points to.
*......................................................................
The SegmentProperty enumeration provides an elegant means to add,
remove, and query properties of instances of derived classes of the
AbstractSegment class. It is defined as:
typedef enum SegmentProperty
{
present,
executable,
readable,
writable,
big,
expandDown
} SegmentProp_t;
The AbstractSegment class defines members operator+(SegmentProp_t) and
operator-(SegmentProp_t) that allow properties to be added and removed
with a natural syntax. For example, the code
Segment mySeg();
mySeg - present;
creates a descriptor and makes it not present.
*......................................................................
The Segment class corresponds to generic, fully modifiable LDT descriptors.
There are three DPMI services that create such descriptors, and thus
three constructors for the class. The first corresponds to DPMI function
0000, which allocates a descriptor. The second corresponds to DPMI
function 000Dh, which allocates a specific descriptor. The last
constructor corresponds to DPMI function 000Ah, which creates an alias
(same base and limit) to an existing segment.
The default properties are present and writable. New Segments have a
base of zero and a size of one.
The argument for the resize method is in bytes, and size==0
specifies a size of 64 KB.
Specific descriptors must be in the range 04h to 0FFh.
*......................................................................
The CommonRealSegment class corresponds to descriptors created by DPMI
function 0002h, Convert Paragraph to Selector. The intended use of
this function is to provide addressability from protected mode for
commonly accessed regions of the low megabyte, such as the BIOS data
area (paragraph 40h) or the video display area (B800h etc.).
DPMI restricts modification of descriptors created by function 0002h, and
therefore the resize, move, operator+(SegmentProp_t) and
operator-(SegmentProp_t) members all return FALSE. Other members are
inherited from AbstractSegment.
*......................................................................
The DOSMemory class corresponds to DPMI function 100h. The constructor
uses this function to allocate a block of memory from DOS. DPMI provides
a descriptor that allows addressability of the block from protected mode.
The argument to the constructor is the desired size in paragraphs of the
block. If the allocation fails, the ptrTo function returns zero. The
paragraph address of the block is available via the segmentBase(void)
member inherited from AbstractSegment.
This code fragment:
DOSMemory d(0x100);
char far *p = (char far *)d.ptrTo();
allocates 0x100 paragraphs of DOS memory and initializes a pointer to
it. If the allocation fails, p is a null pointer.
The resize member for DOSMemory maps to DPMI function 102h, Resize DOS
Memory Block; similarly, the destructor maps to function 101h, Free
DOS Memory Block. Because DPMI restricts any other modifications to these
blocks, the operator+(SegmentProp_t), operator-(SegmentProp_t), and move
members all return FALSE;
*......................................................................
A HugeSegment corresponds to a set of consecutive descriptors, which are
set up to span a address region of arbitrary size. The difference between
the base addresses of consecutive descriptors is 64 KB. The argument to
the constructor is the size in bytes of the segment.
For example, the code fragment
HugeSegment h(0x28000);
h.move(0x500000);
results in the allocation of three descriptors having sizes of 0x10000,
0x10000, and 0x8000. Calling the move member sets the base addresses
of the three descriptors to 0x500000, 0x510000, and 0x520000.
Operations on a HugeSegment, such as adding or removing a property,
affect all of its component descriptors. Likewise, the destructor
frees all the descriptors.
HugeSegments cannot be grown if the new desired size requires additional
descriptors to span the region. Shrinking a HugeSegment frees descriptors
no longer required to span it, and these cannot be reallocated to
return the segment to its original size.
*......................................................................
A MemorySegment is a generic descriptor mapped to a block of DPMI memory.
The size is restricted by the argument to the constructor to be 64 KB
or less. Declaring a MemorySegment results in allocating both memory
and a descriptor initialized to address that memory.
The code fragment
MemorySegment m(0x500);
short far *p = (short far *)m.ptrTo();
makes p a far pointer to a 0x500 byte block of memory. An zero argument
to the constructor requests a 64 KB block.
An alternate constructor allows the MemorySegment to be allocated with
a specific descriptor.
The resize and property members work as expected, but the move member
returns FALSE since DPMI provides no means to move memory blocks.
*......................................................................
A HugeMemorySegment is to a MemorySegment as a HugeSegment is to a
Segment. A HugeMemorySegment is an arbitrarily large block of memory
with a set of consecutive descriptors that are set up to span it. The
argument to the constructor is the size in bytes. As for MemorySegment,
the move member returns FALSE.
HugeMemorySegments cannot be grown if the new desired size requires
additional descriptors to span the region. Shrinking a HugeMemorySegment
frees descriptors no longer required to span it, and these cannot be
reallocated to return the segment to its original size.
*--------------------------------------------------------------------
Header File: REALPROC.H See example XREAL
Classes Members
------- -------
RealProcedure
RealProcedure Constructor.
operator() Call operator invokes real
mode procedure.
operator char() char cast extracts char return
value from real mode call structure.
operator int() int cast extracts int return
value from real mode call structure.
operator long() long cast extracts long return
value from real mode call structure.
Applications occasionally require certain routines that cannot run in
real mode, and must switch to real mode to execute them. The RealProcedure
class corresponds to DPMI mechanisms for invoking (far) functions in
real mode.
The arguments for the constructor are the address of the real procedure
and the number of bytes of arguments the real procedure expects on the
stack when it is invoked. The second argument is optional and defaults
to zero. The procedure address is near, and is assumed to be in the
default code segment.
To invoke the RealProcedure, simply call it. The class overrides the
call operator, and the member operator() makes the necessary DPMI calls
to run the registered routine in real mode. The stack arguments, if any,
are copied to the stack on which the real mode routine is invoked.
The class ensures that DS==SS when the real mode routine executes. Thus
the real mode routine can use any near pointers.
An additional feature of the RealProcedure class is the ability to
return values. Each class instance contains a dpmiRegs_t structure that
is used to pass the register state between modes. Upon return to protected
mode, this structure holds the register state in effect when the real
routine returned, and return values are contained therein. To access
them, use the cast override members: operator char(), operator int() and
operator long(). Refer to the example code to see exactly how this is done.
*--------------------------------------------------------------------
Header File: REALINT.H See example XREAL
Classes Members
------- -------
RealInterrupt
RealInterrupt Constructor
operator() Call operator invokes interrupt
handler in real mode.
A RealInterrupt corresponds to the DPMI function that switches to
real mode and issues a particular interrupt after installing a
register state supplied by the caller. Unlike the RealProcedure class,
the interface to RealInterrupt assumes register-based argument passing.
The argument to the constructor is the number of the interrupt, from
zero to 255. The member operator() (call override operator) is used
to invoke the real mode interrupt. This requires a dpmiRegs_t
structure as an argument. Upon return from the interrupt, the dpmiRegs_t
structure reflects the register state at the time the real mode
interrupt handler returned.
The caller is required to set up the dpmiRegs_t structure that is passed
when the real interrupt is called. This includes setting up the stack
(SS:SP fields) and the flags. Setting SS and SP requests the DPMI host
to provide a stack. The flags value should be chosen carefully,
especially with regard to the Interrupt Enable bit and the Trace bit.
An example of using a RealInterrupt is included in the TestCallBack function
of the XREAL.CPP example.
*--------------------------------------------------------------------
Header File: CALLBACK.H See example XREAL
Classes Members
------- -------
CallBack CallBack Constructor; allocates real mode
call-back and initialize register
structure; saves callback address
~CallBack Destructor; releases call back.
getCallBackAddress Returns the call back address.
DPMI provides a mechanism for call protected mode routines from real
mode. Unfortunately, the mechanism is rather complex. The CallBack
class goes a long way in simplifying the task of using real mode
call backs.
The single arguemnt to the constructor is the address of the call back
handler. The call back handler is a routine that called from real mode
but runs in protected mode. The class includes dispatching logic that
allows you to code the handler as a normal near routine, and allows you to
assume that DS==SS. The argument to the handler is a dpmiRegs_t
structure that reflects the interrupt state at the time of the call.
Any changes the handler makes to this structure are reflected in the
register state when the handler returns to real mode.
The handler should only be invoked by calling to the far callback address
from real mode. The callback address is obtained with the getCallBackAddress
member. See function TestCallBack in the XREAL example.
*......................................................................
Header File: DPMIINT.H See examples XINTR, XREAL
Classes Members
------- -------
InterruptHandler
InterruptHandler Constructor; hooks interrupt.
~InterruptHandler Destructor; unhooks interrupt.
callPrevious Invokes previous handler.
RealInterruptHandler
: InterruptHandler
RealInterruptHandler Constructor; hooks real interrupt.
~RealInterruptHandler Destructor; unhooks real interrupt.
The interrupt handling classes make it very easy to create handlers for
hardware and software interrupts, both in real mode and protected mode.
The class handles all the necessary interaction with DPMI for saving the
previous vector, and for setting the interrupt vector to the user's handler.
The class further simplifies creation of handlers by allowing the user
to code the handler as a normal function, i.e, the user does not need to
declare it as _interrupt, and may assume that DS==SS, which is important
in small model programs. This is accomplished by the interrupt dispatching
logic built into the class (see Implementation Notes for more information).
The arguments to the constructor are the interrupt number and the address
of the routine that the user assigns to handle the interrupt. The argument
to the user's handler routine is a dpmiRegs_t structure, which reflects
the register state at the time the interrupt occurs. Changes to the
dpmiRegs_t argument made by the handler are reflected as changes to the
register state when the handler returns. For example, a software interrupt
handler that returns a value in AX modifies the drAX field of the dpmiRegs_t
argument. Likewise, a hardware interrupt handler which preserves the
register state must make no changes to the dpmiRegs_t argument.
The member callPrevious is useful for calling the handler that was in
effect when the user handler was created. The argument to callPrevious
is a pointer to the dpmiRegs_t structure, which is necessary in order
to present the correct register state to the previous handler. Any changes
made to the register state by the previous handler are reflected in the
dpmiRegs_t structure upon return. RealInterruptHandlers inherit this member.
The destructors restore the previous vector.
*--------------------------------------------------------------------
Header file: EXCEPTIO.H See example XCEPT
Classes Members
------- -------
ExceptionHandler
ExceptionHandler Constructor. Hooks exception.
~ExceptionHandler Destructor. Restores vector
callPrevious Invokes previous handler.
The ExceptionHandler class makes it easy to create handlers for
processor exceptions, such as General Protection violation, Segment
Not Present, etc. As with InterruptHandlers, the class provides
dispatching such that handlers run with DS==SS, so that all near pointers
are valid, and handlers are declared as normal near functions.
The arguments to the constructor are the exception number to handle,
and the address of the handler. The class takes care of calling DPMI
to get the previous vector and set up for the new handler.
When the handler is invoked, there are two structures passed to it. The
first is a dpmiRegs_t structure which reflects the register state at
the time the exception occurred. The second is the DPMI exception
frame, which gives the CS:IP, SS:SP, and flags at the time of the
exception. The handler may modify fields in the register structure
and/or the exception frame structure, and such changes are observed
by the host when the handler returns.
The member callPrevious is used to invoke the previous handler for the
exception. It is passed pointers to the register state and to the
exception frame, which it may modify.